home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Camera.p < prev    next >
Text File  |  1997-03-19  |  47KB  |  1,701 lines

  1. unit Camera;
  2.  
  3. {Routines used by the NIH Image to support Data Translation
  4. and Scion (LG-3, AG-5 or VG-5) frame grabber cards, and
  5. QuickTime compatible digitizers.}
  6.  
  7. interface
  8.  
  9.  
  10.     uses
  11.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  12.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  13.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  14.         QDOffscreen, Components, QuickTimeComponents, ImageCompression, GestaltEqu, OSUtils,
  15.         globals, Utilities, Graphics, File1, Analysis, Lut;
  16.  
  17.  
  18.     function DoAveragingOptions: boolean;
  19.     procedure AverageFrames;
  20.     procedure GetFrame;
  21.     procedure CaptureAndDisplayFrame;
  22.     procedure HighlightPixels;
  23.     procedure ShowTriggerMessage;
  24.     procedure StartDigitizing;
  25.     procedure StopDigitizing;
  26.     function GetFGPixel (h, v: integer): integer;
  27.     procedure WaitForTrigger;
  28.     procedure ShowChannel;
  29.     procedure ShowVideoControl;
  30.     procedure UpdateVideoControl;
  31.     procedure DoVideoControl (item: integer);
  32.     procedure SelectCameraWindow;
  33.     procedure SetOffset (var offset, gain: integer);
  34.     procedure SetGain (var offset, gain: integer);
  35.     procedure ShowOffsetAndGain (offset, gain: integer);
  36.     procedure ShowVideoDialog;
  37.     procedure StartFrame;
  38.     procedure StopFrame;
  39.  
  40.  
  41.  
  42. implementation
  43.  
  44. type
  45.     IntPtr = ^integer;
  46.  
  47. var
  48.     SavePicBaseAddr: ptr;
  49.     StopFlagLoc: IntPtr;
  50.  
  51.  
  52. procedure GetGrabDepth(var bitDepth: LongInt);
  53. var
  54.     vdigInfo: DigitizerInfo;
  55. begin
  56.     if VDGetDigitizerInfo(vdig, vdigInfo) = noErr then begin
  57.         if DigitizerMode = digitizeGrayscale then begin
  58.             if band(vdigInfo.outputCapabilityFlags, digiOutDoes8) <> 0 then
  59.                 bitDepth := 8 {first choice}
  60.             else if band(vdigInfo.outputCapabilityFlags, digiOutDoes32) <> 0 then
  61.                 bitDepth := 32 {second choice}
  62.             else if (band(vdigInfo.outputCapabilityFlags, digiOutDoes16) <> 0) then
  63.                     bitDepth := 16; {last choice}
  64.         end else begin {capture color}
  65.             if band(vdigInfo.outputCapabilityFlags, digiOutDoes32) <> 0 then
  66.                 bitDepth := 32 {first choice}
  67.             else if band(vdigInfo.outputCapabilityFlags, digiOutDoes16) <> 0 then
  68.                 bitDepth := 16 {second choice}
  69.             else if (band(vdigInfo.outputCapabilityFlags, digiOutDoes8) <> 0) then
  70.                     bitDepth := 8; {last choice}
  71.         end;
  72.     end;
  73.     ShowMessage(StringOf('grab depth=', bitDepth));
  74. end;
  75.  
  76.  
  77. procedure SetVideoStandard;
  78. var
  79.     err: ComponentResult;
  80.     inFlags, outFlags: LongInt;
  81.     vdigInfo: DigitizerInfo;
  82. begin
  83.     if VDGetDigitizerInfo(vdig, vdigInfo) <> noErr then
  84.         exit(SetVideoStandard);
  85.     case DigitizerStandard of
  86.         NTSCStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesNTSC) <> 0 then
  87.                         err := VDSetInputStandard(vdig, ntscIn);
  88.         PALStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesPAL) <> 0 then
  89.                         err := VDSetInputStandard(vdig, palIn);
  90.         SECAMStd: if band(vdigInfo.inputCapabilityFlags, digiInDoesSECAM) <> 0 then
  91.                         err := VDSetInputStandard(vdig, secamIn);
  92.         otherwise;
  93.     end;
  94.     err := VDGetCurrentFlags(vdig, inFlags, outFlags);
  95.     if err = noErr then
  96.         if band(inFlags, digiInDoesNTSC) <> 0 then
  97.                         DigitizerStandard := NTSCStd
  98.         else if band(inFlags, digiInDoesPAL) <> 0 then
  99.                         DigitizerStandard := PALStd
  100.         else if band(inFlags, digiInDoesSECAM) <> 0 then
  101.                         DigitizerStandard := SECAMStd;
  102. end;
  103.  
  104.  
  105. procedure SetVideoInput;
  106. var
  107.     err: ComponentResult;
  108.     maxChannel, currentChannel: integer;
  109. begin
  110.     err := VDGetNumberOfInputs(vdig, maxChannel);
  111.     if (VideoChannel <= maxChannel) and (err = noErr) then
  112.         err := VDSetInput(vdig, VideoChannel)
  113.     else begin
  114.         VideoChannel := 0;
  115.         err := VDSetInput(vdig, 0);
  116.     end;
  117.     err := VDGetInput(vdig, currentChannel);
  118.     if err = noErr then
  119.         VideoChannel := currentChannel;
  120. end;
  121.  
  122.  
  123. function SetupVdig: boolean;
  124. var
  125.     mPtr: MatrixRecordPtr;
  126.     vdErr: ComponentResult;
  127.     vdigInfo: DigitizerInfo;
  128.     DummyMatrixRecord, bitDepth: LongInt;
  129.     err: OSErr;
  130.     flags: GWorldFlags;
  131.     SaveGDevice: GDHandle;
  132.     gwRect, srcRrect: rect;
  133.     str: str255;
  134. begin
  135.    SetupVdig := false;
  136.     SetRect(gwRect, 0, 0, fgWidth, fgHeight);
  137.     bitDepth := 8;
  138.     GetGrabDepth(bitDepth);
  139.     SetVideoInput;
  140.     if bitDepth = 8 then
  141.         vdErr := VDSetInputColorSpaceMode(vdig, 0); {grayscale}
  142.     SaveGDevice := GetGDevice;
  143.     SetGDevice(osGDevice);
  144.     if bitDepth = 8 then
  145.         GWorldLUT := GetCTable(40) {grayscale LUT}
  146.     else
  147.         GWorldLUT := nil;
  148.     flags := 0;
  149.     err := NewGWorld(osGWorld, bitDepth, gwRect, GWorldLUT, nil, flags);
  150.     SetGDevice(SaveGDevice);
  151.     if err <> NoErr then begin
  152.             PutMemoryAlert;
  153.             CloseVdig;
  154.             exit(SetupVdig);
  155.         end;
  156.     fgPixMap := GetGWorldPixMap(osGWorld);
  157.     if not LockPixels(fgPixMap) then begin
  158.             CloseVdig;
  159.             exit(SetupVdig);
  160.         end;
  161.     {err := LockMemoryContiguous(GetPixBaseAddr(fgPixMap), 2097152);}
  162.     vdErr := VDGetActiveSrcRect(vdig, 0, srcRrect);
  163.     if vdErr = noErr then
  164.         vdErr := VDSetDigitizerRect(vdig, srcRrect);
  165.     DummyMatrixRecord := LongInt(nil);
  166.     mPtr := MatrixRecordPtr(ptr(DummyMatrixRecord));
  167.     vdErr := VDSetPlayThruDestination(vdig, fgPixMap, gwRect, MatrixRecord(mPtr^), nil);
  168.     if vdErr = noErr then
  169.         SetupVdig := true
  170.     else begin
  171.         CloseVdig;
  172.         if vdErr = -2208 then
  173.             str := concat(cr, '(Try turning virtual memory or RAM Doubler off.)')
  174.         else
  175.             str := '';
  176.         PutError(StringOf('Video digitizer error ', vdErr, str));
  177.     end;
  178. end;
  179.  
  180.  
  181. procedure LookForVDig(var vdigError: boolean);
  182. {Look for a QuickTime video digitizer component}
  183. var
  184.     result: LongInt;
  185.     videoDesc: ComponentDescription;
  186.     srcRrect: rect;
  187.     vdErr: ComponentResult;
  188.     vdigID: Component;
  189. begin
  190.    vdigError := false;
  191.     if Gestalt(gestaltQuickTime, result) <> noErr then begin
  192.         ShowMessage('No QuickTime');
  193.         exit(LookForVDig);
  194.     end;
  195.     {$IFC PowerPC}
  196.     if Gestalt(gestaltQuickTimeFeatures, result) <> noErr then begin
  197.         ShowMessage('No QuickTime PPC support');
  198.         exit(LookForVDig);
  199.     end;
  200.     {$ENDC}
  201.     videoDesc.componentType := VideoDigitizerComponentType;
  202.     videoDesc.componentSubType := OSType(0); {any subtype}
  203.     if UseBuiltinDigitizer then
  204.         videoDesc.componentManufacturer := 'appl'
  205.     else
  206.         videoDesc.componentManufacturer := OSType(0);
  207.     videoDesc.componentFlags := 0;
  208.     videoDesc.componentFlagsMask := 0;
  209.     vdigID :=FindNextComponent(Component(0), videoDesc);
  210.     if vdigID = Component(0) then begin
  211.         videoDesc.componentManufacturer := OSType(0); {any manufacturer}
  212.         vdigID :=FindNextComponent(Component(0), videoDesc);
  213.         if vdigID = Component(0) then begin
  214.             ShowMessage('No vdig found');
  215.             exit(LookForVDig);
  216.         end;
  217.     end;
  218.     vdig := OpenComponent(vdigID);
  219.     if vdig = nil then begin
  220.       ShowMessage('Unable to open vdig');
  221.       vdigError := true;
  222.         exit(LookForVDig);
  223.     end;
  224.     SetVideoStandard;
  225.     vdErr := VDGetDigitizerRect(vdig, srcRrect);
  226.     {vdErr := VDGetActiveSrcRect(vdig, 0, srcRrect);}
  227.     if vdErr = noErr then with srcRrect do begin
  228.         fgWidth := (right - left) div fgScale;
  229.         fgHeight := (bottom - top) div fgScale;
  230.     end else begin
  231.         fgWidth := 320;
  232.         fgHeight := 240;
  233.     end;
  234.     FrameGrabber := QTvdig;
  235.     if not SetupVdig then
  236.         vdigError := true;
  237.     HighlightSaturatedPixels := false;
  238. end;
  239.  
  240.  
  241. procedure CorrectShadingOfLine (PicPtr, BFPtr: ptr; width, BFMean: integer);
  242. {$IFC PowerPC}
  243. VAR
  244.   PicLine,BFLine:LinePtr;
  245.   i,value:LongInt;
  246. BEGIN
  247.   PicLine:=LinePtr(PicPtr);
  248.   BFLine:=LinePtr(BFPtr);
  249.   FOR i:=0 TO width-1 DO BEGIN
  250.     value:=PicLine^[i];
  251.     value:=255-value;
  252.     value:=(value * BFMean + (BFLine^[i] div 2)) DIV BFLine^[i];
  253.     IF value>254 THEN value:=254;
  254.     IF value<1 THEN value:=1;
  255.     PicLine^[i]:=255-value;
  256.   END;
  257. END;
  258. {$ELSEC}
  259.   {a0=data pointer}
  260.   {a1=blank field data pointer}
  261.   {d0=count}
  262.   {d1=pixel value}
  263.   {d2=blank field pixel value}
  264.   {d3=blank field mean}
  265.   {d4=temp}
  266.   {d5=max pixel value(245)}
  267.   {d6=min pixel value(1)}
  268.     inline
  269.         $4E56, $0000, {   link    a6,#0}
  270.         $48E7, $FEC0, {   movem.l    a0-a1/d0-d6,-(sp)}
  271.         $206E, $000C, {   move.l    12(a6),a0}
  272.         $226E, $0008, {   move.l    8(a6),a1}
  273.         $4280,       {   clr.l    d0}
  274.         $302E, $0006, {   move.w    6(a6),d0}
  275.         $362E, $0004, {   move.w    4(a6),d3}
  276.         $2A3C, $0000, $00FE, {   move.l    #254,d5}
  277.         $2C3C, $0000, $0001, {   move.l    #1,d6}
  278.         $5380,       {   subq.l    #1,d0}
  279.         $4281,       {   clr.l    d1}
  280.         $4282,       {   clr.l    d2}
  281.         $1210,       {L1    move.b    (a0),d1}
  282.         $1419,       {   move.b    (a1)+,d2}
  283.         $4601,       {   not.b    d1}
  284.         $C2C3,       {   mulu.w    d3,d1}
  285.         $2802,       {   move.l    d2,d4}
  286.         $E244,       {   asr.w    #1,d4}
  287.         $D284,       {   add.l    d4,d1}
  288.         $82C2,       {   divu.w    d2,d1}
  289.         $B245,       {   cmp.w    d5,d1}
  290.         $6F02,       {   ble.s    L2}
  291.         $3205,       {   move.w    d5,d1}
  292.         $B246,       {L2    cmp.w    d6,d1}
  293.         $6C02,       {   bge.s    L3}
  294.         $3206,       {   move.w    d6,d1}
  295.         $4601,       {L3    not.b    d1}
  296.         $10C1,       {   move.b    d1,(a0)+}
  297.         $51C8, $FFDE, {   dbra    d0,L1}
  298.         $4CDF, $037F, {   movem.l    (sp)+,a0-a1/d0-d6}
  299.         $4E5E,       {   unlk    a6}
  300.         $DEFC, $000C; {   add.w    #12,sp}
  301. {$ENDC}
  302.  
  303.  
  304.     procedure CorrectShading;
  305.         var
  306.             i, tag, width: integer;
  307.             offset, NextUpdate: LongInt;
  308.             p1, p2: ptr;
  309.             str: str255;
  310.             MaskRect:rect;
  311.     begin
  312.         with info^ do begin
  313.                 if ImageSize <> BlankFieldInfo^.ImageSize then begin
  314.                         beep;
  315.                         exit(CorrectShading);
  316.                     end;
  317.                 ShowWatch;
  318.                 tag:=0;
  319.                 NextUpdate:=TickCount+6;
  320.                 width:=PicRect.right;
  321.                 p1 := PicBaseAddr;
  322.                 p2 := BlankFieldInfo^.PicBaseAddr;
  323.                 for i := 1 to nLines do begin
  324.                         CorrectShadingOfLine(p1, p2, PixelsPerLine, BlankFieldMean);
  325.                         p1 := ptr(ord4(p1) + info^.BytesPerRow);
  326.                         p2 := ptr(ord4(p2) + BlankFieldInfo^.BytesPerRow);
  327.                     if TickCount>=NextUpdate then begin
  328.                             SetRect(MaskRect, 0, tag, width, i);
  329.                             UpdateScreen(MaskRect);
  330.                             tag:=i;
  331.                             NextUpdate:=TickCount+6;
  332.                         end;
  333.                     end;
  334.                 SetRect(MaskRect, 0, tag, width, nLines);
  335.                 UpdateScreen(MaskRect);
  336.                 str := title;
  337.                 if SpatiallyCalibrated then
  338.                     str := concat(str, chr($13)); {Black Diamond}
  339.                 if fit <> uncalibrated then
  340.                     str := concat(str, '');
  341.                 if wptr <> nil then
  342.                     SetWTitle(wptr, concat(str, ' (Corrected)'));
  343.             end;
  344.     end;
  345.  
  346.  
  347.     procedure CopyVdigImageOffscreen;
  348.     var
  349.         SaveExtraColors: integer;
  350.     begin
  351.         with info^ do begin
  352.                 SaveExtraColors := 0;
  353.                 if (LUTMode = Grayscale) and (not IdentityFunction or (nExtraColors <> 0)) then begin
  354.                     SaveExtraColors := nExtraColors;
  355.                     nExtraColors := 0;
  356.                     ResetGrayMap;
  357.                 end;
  358.                 CopyOffscreen(fgPixMap, osPort^.portPixMap, PicRect, PicRect);
  359.                 if SaveExtraColors <> 0 then begin
  360.                     nExtraColors := SaveExtraColors;
  361.                     LoadLUT(ctable);
  362.                 end;
  363.                 UpdatePicWindow;
  364.         end; {with}
  365.     end;
  366.     
  367.     
  368.     procedure StartFrame;
  369.     begin
  370.         if CurrentBufferIsZero then begin
  371.             if FrameGrabber = ScionAG5 then
  372.                 BufferReg^ := $81
  373.             else
  374.                 BufferReg^ := 0
  375.         end else begin
  376.             if FrameGrabber = ScionAG5 then
  377.                 BufferReg^ := $89
  378.             else
  379.                 BufferReg^ := 1;
  380.         end;
  381.         if ExternalTrigger then begin
  382.             if FrameGrabber = ScionAG5 then
  383.                 ControlReg^ := bor(bor(ord(AG5GrabMode), $90), bsl(ord(AG5LutMode and not ControlKeyDown), 2))
  384.             else
  385.                 ControlReg^ := $90 {Start frame capture}
  386.         end else begin
  387.             if FrameGrabber = ScionAG5 then
  388.                 ControlReg^ := bor(bor(ord(AG5GrabMode), $80), bsl(ord(AG5LutMode and not ControlKeyDown), 2))
  389.             else
  390.                 ControlReg^ := $80; {Start frame capture}
  391.         end;
  392.     end;
  393.  
  394.  
  395.     procedure StopFrame;
  396.         var
  397.             ticks, timeout: LongInt;
  398.     begin
  399.         if ExternalTrigger then begin {Wait for trigger}
  400.                 repeat
  401.                     if button then
  402.                         ExternalTrigger := false;
  403.                 until (BitAnd(ControlReg^, $80) = $80) or not ExternalTrigger;
  404.                 ControlReg^ := 0;
  405.             end {if External Trigger}
  406.         else begin
  407.                 TimeOut := TickCount + 30;  {1/2sec. timeout}
  408.                 while BitAnd(ControlReg^, $80) = 0 do begin    {Wait for it to complete}
  409.                         if TickCount > TimeOut then begin
  410.                                 ControlReg^ := 0;
  411.                                 leave
  412.                             end;
  413.                     end;
  414.                 ControlReg^ := 0;
  415.             end;
  416.         with fgPort^ do
  417.             with PortPixMap^^ do
  418.                 if CurrentBufferIsZero then
  419.                     BaseAddr := ptr(fgSuperSlotBase0)
  420.                 else
  421.                     BaseAddr := ptr(fgSuperSlotBase1);
  422.         CurrentBufferIsZero := not CurrentBufferIsZero;
  423.         fgFrameCount := fgFrameCount + 1;
  424.     end;
  425.  
  426.  
  427.     procedure StopDigitizing;
  428.     begin
  429.         if digitizing then
  430.             with info^ do begin
  431.                     ShowFrameRate('', fgStartTicks, fgFrameCount);
  432.                     if vdig <> nil then
  433.                         CopyVdigImageOffscreen
  434.                     else
  435.                         CopyOffscreen(fgPixMap, osPort^.portPixMap, PicRect, PicRect);
  436.                     SetMenuItemText(SpecialMenuH, StartItem, 'Start Capturing');
  437.                     Digitizing := false;
  438.                     ContinuousHistogram := false;
  439.                     if DoubleBuffering then begin
  440.                         StopFrame;
  441.                         BufferReg^ := 0;
  442.                         CurrentBufferIsZero := true;
  443.                         DoubleBuffering := false;
  444.                         with fgPort^ do
  445.                             with PortPixMap^^ do
  446.                                 BaseAddr := ptr(fgSuperSlotBase0)
  447.                      end;
  448.                     with info^ do
  449.                         if PictureType = FrameGrabberType then begin
  450.                                 title := 'Camera';
  451.                                 UpdateTitleBar;
  452.                                 if HighlightSaturatedPixels then
  453.                                     LoadLUT(ctable);
  454.                             end;
  455.                     if (ScreenDepth<>8) and HighlightSaturatedPixels then
  456.                         UpdatePicWindow;
  457.                     if (BlankFieldInfo <> nil) and not OptionKeyDown then
  458.                         CorrectShading;
  459.                 end;
  460.     end;
  461.  
  462.  
  463.     procedure GetFrame;
  464.         var
  465.             ticks, timeout: LongInt;
  466.             temp:integer;
  467.             vdigErr: ComponentResult;
  468.     begin
  469.             case FrameGrabber of
  470.             
  471.                 ScionLG3, ScionVG5f:
  472.                     if ExternalTrigger then begin {Wait for trigger}
  473.                             ControlReg^ := $90;
  474.                             repeat
  475.                                 if button then
  476.                                     ExternalTrigger := false;
  477.                             until (band(ControlReg^, $80) = $80) or not ExternalTrigger;
  478.                             ControlReg^ := 0;
  479.                             if Digitizing then
  480.                                 StopDigitizing;
  481.                             UpdateVideoControl;
  482.                         end {if External Trigger}
  483.                     else begin
  484.                             TimeOut := TickCount + 30;  {1/2sec. timeout}
  485.                             ControlReg^ := $80; {Start frame capture}
  486.                             while band(ControlReg^, $80) = 0 do begin    {Wait for it to complete}
  487.                                     if TickCount > TimeOut then begin
  488.                                             ControlReg^ := 0;
  489.                                             leave
  490.                                         end;
  491.                                 end;
  492.                             ControlReg^ := 0;
  493.                         end;
  494.                 
  495.             ScionAG5:
  496.                     if ExternalTrigger then begin {Wait for trigger}
  497.                             ControlReg^ := bor(bor(ord(AG5GrabMode), $90), bsl(ord(AG5LutMode and not ControlKeyDown), 2));
  498.                             repeat
  499.                                 if button then
  500.                                     ExternalTrigger := false;
  501.                             until (band(ControlReg^, $80) = $80) or not ExternalTrigger;
  502.                             ControlReg^ := 0;
  503.                             if Digitizing then
  504.                                 StopDigitizing;
  505.                             UpdateVideoControl;
  506.                         end {if External Trigger}
  507.                     else begin
  508.                             TimeOut := TickCount + 30;  {1/2sec. timeout}
  509.                             ControlReg^ := bor(bor(ord(AG5GrabMode), $80), bsl(ord(AG5LutMode and not ControlKeyDown), 2)); {Start frame capture}
  510.                             repeat
  511.                                 if TickCount > TimeOut then
  512.                                     leave;
  513.                                 temp:=ControlReg^; {ppc-bug}
  514.                             until band(temp, $80) <> 0; {Wait for it to complete}
  515.                             ControlReg^ := 0;
  516.                         end;
  517.                         
  518.             QuickCapture:
  519.                 if ExternalTrigger then begin {Wait for trigger}
  520.                         ControlReg^ := $82; {Set Busy and External Trigger Enable bits}
  521.                         repeat
  522.                             if button then
  523.                                 ExternalTrigger := false;
  524.                             temp:=ControlReg^; {ppc-bug}
  525.                         until (band(temp, $80) = 0) or not ExternalTrigger;
  526.                         if Digitizing then
  527.                             StopDigitizing;
  528.                         UpdateVideoControl;
  529.                     end {if External Trigger}
  530.                 else begin
  531.                         TimeOut := TickCount + 30;  {1/2sec. timeout}
  532.                         ControlReg^ := $80; {Start frame capture by setting busy bit}
  533.                         repeat
  534.                             if TickCount > TimeOut then
  535.                                 leave;
  536.                             temp:=ControlReg^; {ppc-bug}
  537.                         until band(temp, $80) = 0; {Wait for frame capture to complete}
  538.                     end;
  539.             
  540.             QTvdig: begin
  541.                             if ExternalTrigger then begin {Wait for mouse press}
  542.                                 repeat
  543.                                 until button;
  544.                                 ExternalTrigger := false;
  545.                             end;
  546.                             if vdig <> nil then
  547.                                 vdigErr := VDGrabOneFrame(vdig);
  548.                     end;
  549.                 
  550.         end; {case}
  551.         fgFrameCount := fgFrameCount + 1;
  552.     end;
  553.  
  554.  
  555.     procedure CaptureAndDisplayFrame;
  556.         var
  557.             tPort: GrafPtr;
  558.             SaveGDevice: GDHandle;
  559.     begin
  560.         with info^ do begin
  561.                 if (PictureType <> FrameGrabberType) or (PixelsPerLine <> fgWidth) or (nlines <> fgHeight) then begin
  562.                         Digitizing := false;
  563.                         exit(CaptureAndDisplayFrame);
  564.                     end;
  565.                 if DoubleBuffering then begin
  566.                     StopFrame;
  567.                     StartFrame;
  568.                  end else
  569.                     GetFrame;
  570.                 SaveGDevice := GetGDevice;
  571.                 SetGDevice(GetMainDevice);
  572.                 getPort(tPort);
  573.                 SetPort(wptr);
  574.                 SetFColor(BlackIndex);
  575.                 SetBColor(WhiteIndex);
  576.                 if (FrameGrabber = QTvdig) and (LUTMode <> grayscale) and (ScreenDepth <= 8) then
  577.                     CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, ditherCopy, nil)
  578.                 else
  579.                     CopyBits(BitMapHandle(fgPixMap)^^, BitMapHandle(CGrafPtr(wptr)^.PortPixMap)^^, SrcRect, wrect, srcCopy, nil);
  580.                 SetPort(tPort);
  581.                 SetGDevice(SaveGDevice);
  582.             end;
  583.     end;
  584.  
  585.  
  586.     procedure SetReg (index, value: integer);
  587.         const
  588.             RegOffset = $f5fe0;
  589.         var
  590.             reg: ptr;
  591.     begin
  592.         reg := ptr(fgSlotBase + RegOffset + index * 4);
  593.         reg^ := value;
  594.     end;
  595.  
  596.  
  597.     {$ifc PowerPC} {ppc-bug}
  598.     procedure SwapMMUMode(var mode:SignedByte);
  599.     begin
  600.     end;
  601.     {$endc}
  602.     
  603.     
  604.     procedure SelectCameraWindow;
  605.   {If there is a Camera window, activate it, otherwise, do nothing.}
  606.         var
  607.             i: integer;
  608.             TempInfo: InfoPtr;
  609.     begin
  610.         for i := 1 to nPics do begin
  611.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  612.                 if TempInfo^.PictureType = FrameGrabberType then begin
  613.                         if PicWindow[i] <> nil then begin
  614.                                 if OpPending then
  615.                                     KillRoi;
  616.                                 SelectWindow(PicWindow[i]);
  617.                                 Info := TempInfo;
  618.                                 ActivateWindow;
  619.                             end; {if}
  620.                         leave;
  621.                     end; {if}
  622.             end; {for}
  623.     end;
  624.  
  625.  
  626.     procedure HighlightPixels;
  627.         var
  628.             lut: MyCSpecArray;
  629.     begin
  630.         with info^ do begin
  631.                 lut := ctable;
  632.                 lut[1].rgb := Highlight1;
  633.                 lut[254].rgb := Highlight254;
  634.                 LoadLUT(lut);
  635.             end;
  636.     end;
  637.  
  638.  
  639.     procedure ShowTriggerMessage;
  640.     begin
  641.         if ExternalTrigger and (frameGrabber <> noFrameGrabber) then
  642.             ShowMessage(concat('EXTERNAL TRIGGER MODE', crStr, '(Press mouse button to exit)'));
  643.     end;
  644.  
  645.  
  646.     procedure StartDigitizing;
  647.         var
  648.             i, width, height: integer;
  649.             trect: rect;
  650.             NewWindow: boolean;
  651.             vdigError: boolean;
  652.     begin
  653.         if FrameGrabber = NoFrameGrabber then begin
  654.             LookForVDig(vdigError);
  655.             if vdigError then
  656.                 exit(StartDigitizing);
  657.         end;
  658.         if FrameGrabber = NoFrameGrabber then begin
  659.                 PutError('Capturing requires a Data Translation, Scion or QuickTime compatible frame grabber.');
  660.                 AbortMacro;
  661.                 exit(StartDigitizing)
  662.             end;
  663.         if Digitizing then begin
  664.                 StopDigitizing;
  665.                 if BlankFieldInfo <> nil then
  666.                     wait(15);
  667.                 FlushEvents(EveryEvent, 0); {In case user holds key down too long}
  668.                 exit(StartDigitizing)
  669.             end;
  670.         if info^.PictureType <> FrameGrabberType then
  671.             SelectCameraWindow;
  672.         NewWindow := false;
  673.         with info^ do
  674.             if (PictureType <> FrameGrabberType) or (PixelsPerLine <> fgWidth) or (nlines <> fgHeight) then begin
  675.                     if not NewPicWindow('Camera', fgWidth, fgHeight) then
  676.                         exit(StartDigitizing);
  677.                     if FrameGrabber = QTvdig then with info^ do begin
  678.                         fgPort := osPort;
  679.                         fgSlotBase := LongInt(PicBaseAddr);
  680.                         fgRowBytes := BytesPerRow;
  681.                     end;
  682.                     NewWindow := true;
  683.                 end;
  684.         with info^ do begin
  685.                 PictureType := FrameGrabberType;
  686.                 if NewWindow and (not EqualRect(SrcRect, PicRect)) then {Center Frame}
  687.                     with SrcRect do begin
  688.                             width := right - left;
  689.                             height := bottom - top;
  690.                             left := (PicRect.right - width) div 2;
  691.                             right := left + width;
  692.                             top := (PicRect.bottom - height) div 2;
  693.                             bottom := top + height;
  694.                         end;
  695.                 KillRoi;
  696.                 if ScaleToFitWindow then
  697.                     ScaleToFit;
  698.                 with SrcRect do begin
  699.                         width := right - left;
  700.                         left := band(left, $fffc);
  701.                         right := left + width;
  702.                     end;
  703.                 GetWindowRect(wptr, trect);
  704.                 with trect do
  705.                     if band(left, 3) <> 0 then
  706.                         MoveWindow(wptr, band(left, $fffc), top, true); {Forces window to be word aligned}
  707.                 with SrcRect do {Prevents bus errors when Camera window moved.}
  708.                     if (top = 0) and (bottom < PicRect.bottom) then begin
  709.                             top := top + 1;
  710.                             bottom := bottom + 1;
  711.                         end;
  712.                 ResetFrameGrabber;
  713.                 Digitizing := true;
  714.                 SetMenuItemText(SpecialMenuH, StartItem, 'Stop Capturing');
  715.                 changes := true;
  716.                 BinaryPic := false;
  717.                 UpdateTitleBar;
  718.                 if HighlightSaturatedPixels then
  719.                     HighlightPixels;
  720.             end; {with info}
  721.         fgFrameCount := 0;
  722.         fgStartTicks := TickCount;
  723.         ContinuousHistogram := false;
  724.         ShowTriggerMessage;
  725.         if PCIFramegrabber and not ExternalTrigger then begin
  726.             DoubleBuffering := true;
  727.             CurrentBufferIsZero := true;
  728.             StartFrame;
  729.         end;
  730.     end;
  731.  
  732.  
  733.     procedure AddLineToSum (src, dst: ptr; width: LongInt);
  734. {$IFC PowerPC}
  735.         type
  736.             SumLineType = array[0..2047] of integer;
  737.             fptr = ^SumLineType;
  738.         var
  739.             FrameLine: LinePtr;
  740.             SumLine: fptr;
  741.             i: integer;
  742.     begin
  743.         FrameLine := LinePtr(src);
  744.         SumLine := fptr(dst);
  745.         for i := 0 to width - 1 do
  746.             SumLine^[i] := SumLine^[i] + FrameLine^[i];
  747.     end;
  748. {$ELSEC}
  749. inline
  750. {a0=data pointer}
  751. {a1=sum buffer pointer}
  752. {d0=count}
  753. {d1=pixel value}
  754. {d2=temp}
  755.     $4E56, $0000, {link    a6,#0}
  756.     $48E7, $E0C0, {movem.l    a0-a1/d0-d2,-(sp)}
  757.     $206E, $000C, {move.l    12(a6),a0}
  758.     $226E, $0008, {move.l    8(a6),a1}
  759.     $202E, $0004, {move.l    4(a6),d0}
  760.     $5380,              {subq.l    #1,d0}
  761.     $4281,              {clr.l    d1}
  762.     $4282,              {clr.l    d2}
  763.     $1218,              {L1    move.b    (a0)+,d1}
  764.     $3411,              {move.w    (a1),d2}
  765.     $D441,              {add.w      d1,d2}
  766.     $32C2,              {move.w    d2,(a1)+}
  767.     $51C8, $FFF6, {dbra    d0,L1}
  768.     $4CDF, $0307, {movem.l    (sp)+,a0-a1/d0-d2}
  769.     $4E5E,               {unlk    a6}
  770.     $DEFC, $000C; {add.w    #12,sp}
  771. {$ENDC}
  772.  
  773.  
  774. function DoAveragingOptions: boolean;
  775.     const
  776.         FramesID = 8;
  777.         VideoRateID = 9;
  778.         SumID = 10;
  779.         ShowID = 11;
  780.         FixID = 12;
  781.         MinID = 13;
  782.         MaxID = 14;
  783.         OnChipID = 15;
  784.     var
  785.         mylog: DialogPtr;
  786.         item, i: integer;
  787. begin
  788.     InitCursor;
  789.     mylog := GetNewDialog(140, nil, pointer(-1));
  790.     if not SumFrames then begin
  791.             ShowIntegratedValues := false;
  792.             FixIntegrationScale := false;
  793.         end;
  794.     SetDNum(MyLog, FramesID, FramesToAverage);
  795.     SetDlogItem(mylog, SumID, ord(SumFrames));
  796.     SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging));
  797.     SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues));
  798.     SetDlogItem(mylog, FixID, ord(FixIntegrationScale));
  799.     SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  800.     SetDNum(MyLog, MinID, IntegrationMin);
  801.     SetDNum(MyLog, MaxID, IntegrationMax);
  802.     SelectDialogItemText(MyLog, FramesID, 0, 32767);
  803.     repeat
  804.         ModalDialog(nil, item);
  805.         if item = FramesID then
  806.             FramesToAverage := GetDNum(MyLog, FramesID);
  807.         if item = SumID then begin
  808.                 SumFrames := not SumFrames;
  809.                 if SumFrames then
  810.                     IntegrateOnChip := false
  811.                 else begin
  812.                         FixIntegrationScale := false;
  813.                         ShowIntegratedValues := false;
  814.                     end;
  815.                 SetDlogItem(mylog, SumID, ord(SumFrames));
  816.                 SetDlogItem(mylog, FixID, ord(FixIntegrationScale));
  817.                 SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues));
  818.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  819.             end;
  820.         if item = VideoRateID then begin
  821.                 VideoRateAveraging := not VideoRateAveraging;
  822.                 if VideoRateAveraging then
  823.                     IntegrateOnChip := false;
  824.                 SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging));
  825.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  826.             end;
  827.         if item = ShowID then begin
  828.                 ShowIntegratedValues := not ShowIntegratedValues;
  829.                 if ShowIntegratedValues then begin
  830.                         SumFrames := true;
  831.                         IntegrateOnChip := false;
  832.                     end;
  833.                 SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues));
  834.                 SetDlogItem(mylog, SumID, ord(SumFrames));
  835.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  836.             end;
  837.         if item = FixID then begin
  838.                 FixIntegrationScale := not FixIntegrationScale;
  839.                 if FixIntegrationScale then begin
  840.                         SumFrames := true;
  841.                         IntegrateOnChip := false;
  842.                     end;
  843.                 SetDlogItem(mylog, FixID, ord(FixIntegrationScale));
  844.                 SetDlogItem(mylog, SumID, ord(SumFrames));
  845.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  846.             end;
  847.         if (item = MinID) or (item = MaxID) then begin
  848.                 if item = MinID then
  849.                     IntegrationMin := GetDNum(MyLog, MinID)
  850.                 else
  851.                     IntegrationMax := GetDNum(MyLog, MaxID);
  852.                 SumFrames := true;
  853.                 FixIntegrationScale := true;
  854.                 IntegrateOnChip := false;
  855.                 SetDlogItem(mylog, SumID, ord(SumFrames));
  856.                 SetDlogItem(mylog, FixID, ord(FixIntegrationScale));
  857.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  858.             end;
  859.         if item = OnChipID then begin
  860.                 IntegrateOnChip := not IntegrateOnChip;
  861.                 if IntegrateOnChip then begin
  862.                         SumFrames := false;
  863.                         VideoRateAveraging := false;
  864.                         FixIntegrationScale := false;
  865.                         ShowIntegratedValues := false;
  866.                     end;
  867.                 SetDlogItem(mylog, OnChipID, ord(IntegrateOnChip));
  868.                 SetDlogItem(mylog, SumID, ord(SumFrames));
  869.                 SetDlogItem(mylog, VideoRateID, ord(VideoRateAveraging));
  870.                 SetDlogItem(mylog, FixID, ord(FixIntegrationScale));
  871.                 SetDlogItem(mylog, ShowID, ord(ShowIntegratedValues));
  872.             end;
  873.     until (item = ok) or (item = cancel);
  874.     DisposeDialog(mylog);
  875.     if FramesToAverage < 2 then
  876.         FramesToAverage := 2;
  877.     if IntegrationMin < 0 then
  878.         IntegrationMin := 0;
  879.     if IntegrationMax > 32767 then
  880.         IntegrationMax := 32767;
  881.     if VideoRateAveraging and (item <> cancel) then begin
  882.             if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) then begin
  883.                     VideoRateAveraging := false;
  884.                     PutError('Video rate averaging or summation requires a Scion LG-3 or a Scion AG-5.');
  885.                     DoAveragingOptions := false;
  886.                     exit(DoAveragingOptions);
  887.                 end;
  888.             if (FrameGrabber = ScionLG3) and (FramesToAverage > MaxLG3Frames) then begin
  889.                     FramesToAverage := MaxLG3Frames;
  890.                     DoAveragingOptions := false;
  891.                     PutError(concat('This ', long2str(MaxLG3Frames div 2), 'MB LG-3 can capture a maximum of ', long2str(MaxLG3Frames), ' frames at video rates.'));
  892.                     exit(DoAveragingOptions);
  893.                 end;
  894.             if (FrameGrabber = ScionAG5) and (FramesToAverage > 127) then begin
  895.                     FramesToAverage := 127;
  896.                     DoAveragingOptions := false;
  897.                     PutError(concat('The AG-5 can average or sum a maximum of 127 frames at video rates.'));
  898.                     exit(DoAveragingOptions);
  899.                 end;
  900.         end;
  901.     if IntegrateOnChip and (item <> cancel) then
  902.         if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) and (FrameGrabber <> ScionVG5f)  then begin
  903.                 IntegrateOnChip := false;
  904.                 PutError('On-chip integration requires a Scion frame grabber.');
  905.                 DoAveragingOptions := false;
  906.                 exit(DoAveragingOptions);
  907.             end;
  908.     DoAveragingOptions := item <> cancel;
  909. end;
  910.  
  911.  
  912.  
  913. function OddEven: boolean;
  914. {Looks at the the Field Status bit of the Status Register,
  915. which has the same address as Control Register 1. This bit is
  916. high during the odd field and low during the even field.}
  917. begin
  918.  if band(ControlReg^, $10) = $10 then
  919.   OddEven := true
  920.  else
  921.   OddEven := false;
  922. end;
  923.  
  924.  
  925. procedure WaitForOdd;
  926.  var
  927.   timeout: LongInt;
  928. begin
  929.  TimeOut := TickCount + 30;  {1/2sec. timeout}
  930.  while OddEven do
  931.   if TickCount > TimeOut then
  932.    Exit(WaitForOdd);
  933.  TimeOut := TickCount + 30;  {1/2sec. timeout}
  934.  while not OddEven do
  935.   if TickCount > TimeOut then
  936.    Exit(WaitForOdd);
  937. end;
  938.  
  939.  
  940. procedure IntegrateOn;
  941. {Sets bit 3 (Open Drain Output) of Control Register 1 high
  942. which pulls pin 11 of the 15 pin connector low, causing the
  943. Cohu camera to start integrating.}
  944. begin
  945.  ControlReg^ := $08;
  946. end;
  947.  
  948.  
  949. procedure IntegrateOff;
  950. {Sets bit 3 of Control Register 1 low which open circuits
  951.  pin 11, causing the Cohu camera to stop integrating.}
  952. begin
  953.  ControlReg^ := $00;
  954. end;
  955.  
  956.  
  957. procedure DoOnChipIntegration;
  958. {Requires a Scion LG-3, a Cohu 4910 series camera, and a cable available from Scion.}
  959. var
  960.     i,StartTicks:LongInt;
  961.     str:str255;
  962. begin
  963.     WaitForOdd;
  964.     IntegrateOn;
  965.     StartTicks := TickCount;
  966.     for i := 1 to FramesToAverage - 1 do begin
  967.         WaitForOdd;
  968.         if (i mod 30) = 0 then
  969.             ShowAnimatedWatch;
  970.         if CommandPeriod then
  971.             leave;
  972.     end;
  973.     IntegrateOff;
  974.     GetFrame;
  975.     RealToString((TickCount - StartTicks) / 60.0, 1, 2, str);
  976.     ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str, ' seconds', cr), StartTicks, FramesToAverage);
  977.     with info^ do
  978.         CopyOffscreen(fgPixMap, osPort^.portPixMap, RoiRect, RoiRect);
  979.     UpdatePicWindow;
  980.     KillRoi;
  981.     if BlankFieldInfo <> nil then
  982.         CorrectShading;
  983.     if info^.fit<>uncalibrated then
  984.         RemoveDensityCalibration;
  985. end;
  986.  
  987.  
  988. procedure DoHardwareAveraging;
  989. {Do averaging or integration at video rates using the Scion Ag-5.}
  990. var
  991.   StartTicks,ActualMin,ActualMax:LongInt;
  992.   str1,str2:str255;
  993.   frame,i:integer;
  994.   roi:rect;
  995. begin
  996.     roi:=info^.RoiRect;
  997.     KillRoi;
  998.     if FramesToAverage > 127 then
  999.         FramesToAverage := 127;
  1000.     ExternalTrigger := false;
  1001.     AG5GrabMode := GrabNormal;
  1002.     GetFrame;
  1003.     StartTicks := TickCount;
  1004.     AG5GrabMode := GrabSum;
  1005.     for frame := 1 to FramesToAverage - 1 do begin
  1006.             GetFrame;
  1007.         end;
  1008.     RealToString((TickCount - StartTicks) / 60.0, 1, 2, str2);
  1009.     if not SumFrames then begin
  1010.             ConstantReg^ := FramesToAverage;
  1011.             AG5GrabMode := GrabDivide;
  1012.             GetFrame;
  1013.             AG5GrabMode := GrabNormal;
  1014.             str1 := '';
  1015.         end
  1016.     else begin
  1017.             ActualMin := Ord4(ScaleLowReg^);
  1018.             ActualMax := Ord4(ScaleHighReg^);
  1019.             if FixIntegrationScale then begin
  1020.                     ScaleLowReg^ := integer(IntegrationMin);
  1021.                     ScaleHighReg^ := integer(IntegrationMax);
  1022.                 end;
  1023.             AG5GrabMode := GrabScale;
  1024.             GetFrame;
  1025.             AG5GrabMode := GrabNormal;
  1026.             if FixIntegrationScale then
  1027.                 str1 := concat('min=', long2str(IntegrationMin), ' (', long2str(ActualMin), ')', cr, 'max=', long2str(IntegrationMax), ' (', long2str(ActualMax), ')', cr)
  1028.             else
  1029.                 str1 := concat('min=', long2str(ActualMin), cr, 'max=', long2str(ActualMax), cr)
  1030.         end;
  1031.     ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str1, str2, ' seconds', cr), StartTicks, FramesToAverage);
  1032.     with info^ do
  1033.         CopyOffscreen(fgPixMap, osPort^.portPixMap, roi, roi);
  1034.     UpdatePicWindow;
  1035.     if not EqualRect(roi, info^.PicRect) then
  1036.         RestoreRoi;
  1037.     if BlankFieldInfo <> nil then
  1038.         CorrectShading;
  1039.     if ShowIntegratedValues then with info^ do begin
  1040.             fit := StraightLine;
  1041.             nCoefficients := 2;
  1042.             coefficient[2] := (ActualMax - ActualMin) / 253.0;
  1043.             coefficient[1] := ActualMin - coefficient[2];
  1044.             ZeroClip := false;
  1045.             UpdateTitleBar;
  1046.             if macro then
  1047.                 GenerateValues;
  1048.         end else
  1049.             if SumFrames and (info^.fit<>uncalibrated) then
  1050.                 RemoveDensityCalibration;
  1051.     end; {DoAG5HardwareAveraging}
  1052.     
  1053.  
  1054. procedure AverageFrames;
  1055.     type
  1056.         IntPtr = ^integer;
  1057.         SumLineType = array[0..2047] of integer;
  1058.         sptr = ^SumLineType;
  1059.     var
  1060.         AutoSelectAll: boolean;
  1061.         SelectionSize, FrameBufferSize, offset, StartTicks: LongInt;
  1062.         SumBase, src, srcbase, dst, OffscreenBase: ptr;
  1063.         str1, str2: str255;
  1064.         xLines, xPixelsPerLine, BytesPerLine, frame, line, pixel: integer;
  1065.         aline, BlankLine: LineType;
  1066.         GrabRect: rect;
  1067.         hstart, vstart, wwidth, wheight: integer;
  1068.         j, FramesAveraged: integer;
  1069.         SrcRowBytes, DstRowBytes, i, value, MinV, MaxV, range, ActualMin, ActualMax: LongInt;
  1070.         iptr: IntPtr;
  1071.         FrameLine: LinePtr;
  1072.         SumLine: sptr;
  1073.         SaveBlankFieldInfo: InfoPtr;
  1074.         myMMUMode: signedbyte;
  1075. begin
  1076.     with info^ do
  1077.         if PictureType <> FrameGrabberType then begin
  1078.                 PutError('You must have an active Camera window (created using Start Capturing) in order to average frames.');
  1079.                 AbortMacro;
  1080.                 exit(AverageFrames)
  1081.             end;
  1082.     if NotRectangular or NotinBounds then begin
  1083.             AbortMacro;
  1084.             exit(AverageFrames);
  1085.         end;
  1086.     if (not OptionKeyWasDown) and (not macro) then begin
  1087.             if not DoAveragingOptions then
  1088.                 exit(AverageFrames);
  1089.         end;
  1090.     SaveBlankFieldInfo := BlankFieldInfo;
  1091.     BlankFieldInfo := nil; {We don't want to do shading correction now}
  1092.     StopDigitizing;
  1093.     BlankFieldInfo := SaveBlankFieldInfo;
  1094.     OptionKeyWasDown := false;
  1095.     if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) then
  1096.         VideoRateAveraging := false;
  1097.     if (FrameGrabber <> ScionLG3) and (FrameGrabber <> ScionAG5) and (FrameGrabber <> ScionVG5f) then
  1098.         IntegrateOnChip := false;
  1099.     ShowWatch;
  1100.     ShowTriggerMessage;
  1101.     AutoSelectAll := not Info^.RoiShowing;
  1102.     if AutoSelectAll then
  1103.         SelectAll(false);
  1104.     WhatToUndo := NothingToUndo;
  1105.     ContinuousHistogram := false;
  1106.     ResetFrameGrabber;
  1107.     if IntegrateOnChip then begin
  1108.         DoOnChipIntegration;
  1109.         exit(AverageFrames);
  1110.     end;
  1111.     if VideoRateAveraging and (FrameGrabber=ScionAg5) then begin
  1112.         DoHardwareAveraging;
  1113.         exit(AverageFrames);
  1114.     end;
  1115.     DrawLabels('Frame:', 'Total:', '');
  1116.     with info^.RoiRect do
  1117.         SelectionSize := (ord4(right) - left) * (bottom - top);
  1118.     FrameBufferSize := SelectionSize * 2;
  1119.     if FrameBufferSize > BigBufSize then begin
  1120.             NumToString((FrameBufferSize div 2) div 1024, str1);
  1121.             str1 := concat('It must be enlarged to at least ', str1, 'K bytes.');
  1122.             PutError(concat('The Undo/Clipboard buffer is too small to average the frames. ', str1));
  1123.             if AutoSelectAll or (BlankFieldInfo <> nil) then
  1124.                 KillRoi
  1125.             else
  1126.                 ShowRoi;
  1127.             exit(AverageFrames)
  1128.         end;
  1129.     WhatsOnClip := NothingOnClip;
  1130.     SumBase := BigBuf;
  1131.     with info^, info^.RoiRect do begin
  1132.             offset := left + ord4(top) * BytesPerRow;
  1133.             OffscreenBase := ptr(ord4(PicBaseAddr) + offset);
  1134.             offset := left + ord4(top) * fgRowBytes;
  1135.             srcbase := ptr(ord4(ptr(fgSlotBase)) + offset);
  1136.             SrcRowBytes := fgRowBytes;
  1137.             xLines := bottom - top;
  1138.             xPixelsPerLine := right - left;
  1139.             BytesPerLine := xPixelsPerLine * 2;
  1140.         end; {with}
  1141.     for i := 0 to BytesPerLine - 1 do
  1142.         BlankLine[i] := WhiteIndex;
  1143.     dst := SumBase;
  1144.     for line := 1 to xLines do begin {zero buffer}
  1145.             BlockMove(@BlankLine, dst, BytesPerLine);
  1146.             dst := ptr(ord4(dst) + BytesPerLine);
  1147.         end;
  1148.     info^.title := 'Camera';
  1149.     UpdateTitleBar;
  1150.     StartTicks := TickCount;
  1151.     if VideoRateAveraging then begin
  1152.             if FramesToAverage > MaxLG3Frames then
  1153.                 FramesToAverage := MaxLG3Frames;
  1154.             ExternalTrigger := false;
  1155.             BufferReg^ := 0;
  1156.             GetFrame;
  1157.             StartTicks := TickCount - 2;
  1158.             for frame := 1 to FramesToAverage - 1 do begin
  1159.                     BufferReg^ := Frame;
  1160.                     GetFrame;
  1161.                 end;
  1162.             BufferReg^ := 0;
  1163.             RealToString((TickCount - StartTicks) / 60.0, 1, 2, str1);
  1164.             ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', crStr, str1, ' seconds', crStr), StartTicks, FramesToAverage);
  1165.         end; {if VideoRateAveraging}
  1166.     for frame := 0 to FramesToAverage - 1 do begin
  1167.             Show2Values(frame + 1, FramesToAverage);
  1168.             if VideoRateAveraging then
  1169.                 BufferReg^ := Frame
  1170.             else begin
  1171.                 GetFrame;
  1172.                 if FrameGrabber = QTvdig then with info^ do
  1173.                 CopyOffScreen(fgPixMap, osPort^.portPixMap, roiRect, roiRect);
  1174.             end;
  1175.             src := srcbase;
  1176.             dst := SumBase;
  1177.             myMMUMode := 1;
  1178.             SwapMMUMode(myMMUMode);
  1179.             for line := 1 to xLines do begin
  1180.                     AddLineToSum(src, dst, xPixelsPerLine);
  1181.                     src := ptr(ord4(src) + SrcRowBytes);
  1182.                     dst := ptr(ord4(dst) + BytesPerLine);
  1183.                 end;
  1184.             SwapMMUMode(myMMUMode);
  1185.             if CommandPeriod then begin
  1186.                     beep;
  1187.                     if AutoSelectAll then
  1188.                         KillRoi
  1189.                     else
  1190.                         ShowRoi;
  1191.                     exit(AverageFrames);
  1192.                 end;
  1193.         end; {for}
  1194.     src := SumBase;
  1195.     dst := OffscreenBase;
  1196.     DstRowBytes := info^.BytesPerRow;
  1197.     if SumFrames then begin
  1198.             MinV := 2000000000;
  1199.             MaxV := 0;
  1200.             iptr := IntPtr(src);
  1201.             for i := 1 to SelectionSize do begin
  1202.                     value := iptr^;
  1203.                     if value > MaxV then
  1204.                         MaxV := value;
  1205.                     if value < MinV then
  1206.                         MinV := value;
  1207.                     iptr := IntPtr(ord4(iptr) + 2);
  1208.                 end;
  1209.             ActualMin := MinV;
  1210.             ActualMax := MaxV;
  1211.             if FixIntegrationScale then begin
  1212.                     MinV := IntegrationMin;
  1213.                     MaxV := IntegrationMax;
  1214.                 end;
  1215.             range := MaxV - MinV;
  1216.             if range <> 0 then
  1217.                 for line := 1 to xLines do begin
  1218.                         SumLine := sptr(src);
  1219.                         FrameLine := LinePtr(dst);
  1220.                         for j := 0 to xPixelsPerLine - 1 do begin
  1221.                                 value := ord4(SumLine^[j] - MinV) * 253 div range + 1;
  1222.                                 if value < 0 then
  1223.                                     value := 0;
  1224.                                 if value > 255 then
  1225.                                     value := 255;
  1226.                                 FrameLine^[j] := value;
  1227.                             end;
  1228.                         src := ptr(ord4(src) + BytesPerLine);
  1229.                         dst := ptr(ord4(dst) + DstRowBytes);
  1230.                     end
  1231.             else
  1232.                 beep;
  1233.         end
  1234.     else
  1235.         for line := 1 to xLines do begin
  1236.                 SumLine := sptr(src);
  1237.                 FrameLine := LinePtr(dst);
  1238.                 for j := 0 to xPixelsPerLine - 1 do
  1239.                     FrameLine^[j] := SumLine^[j] div FramesToAverage;
  1240.                 src := ptr(ord4(src) + BytesPerLine);
  1241.                 dst := ptr(ord4(dst) + DstRowBytes);
  1242.             end;
  1243.     if not VideoRateAveraging then begin
  1244.             if SumFrames then begin
  1245.                     if FixIntegrationScale then
  1246.                         str1 := concat('min=', long2str(MinV), ' (', long2str(ActualMin), ')', crStr, 'max=', long2str(MaxV), ' (', long2str(ActualMax), ')', crStr)
  1247.                     else
  1248.                         str1 := concat('min=', long2str(MinV), crStr, 'max=', long2str(MaxV), crStr)
  1249.                 end
  1250.             else
  1251.                 str1 := '';
  1252.             RealToString((TickCount - StartTicks) / 60.0, 1, 2, str2);
  1253.             ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', crStr, str1, str2, ' seconds', crStr), StartTicks, FramesToAverage);
  1254.         end;
  1255.     UpdatePicWindow;
  1256.     if AutoSelectAll then
  1257.         KillRoi
  1258.     else
  1259.         ShowRoi;
  1260.     if BlankFieldInfo <> nil then
  1261.         CorrectShading;
  1262.     if ShowIntegratedValues then with info^ do begin
  1263.             fit := StraightLine;
  1264.             nCoefficients := 2;
  1265.             coefficient[2] := (MaxV - MinV) / 253.0;
  1266.             coefficient[1] := MinV - coefficient[2];
  1267.             nKnownValues := 0;
  1268.             ZeroClip := false;
  1269.             UpdateTitleBar;
  1270.             if macro then
  1271.                 GenerateValues;
  1272.         end else
  1273.             if SumFrames and (info^.fit<>uncalibrated) then
  1274.                 RemoveDensityCalibration;
  1275. end;
  1276.  
  1277.  
  1278. function GetFGPixel (h, v: integer): integer;
  1279.     var
  1280.         offset: LongInt;
  1281.         p: ptr;
  1282. begin
  1283.     if FrameGrabber = QTvdig then begin
  1284.         GetFGPixel := 0;
  1285.         exit(GetFGPixel);
  1286.     end;
  1287.     with Info^ do begin
  1288.             if (h < 0) or (v < 0) or (h >= fgWidth) or (v >= fgHeight) then begin
  1289.                     GetFGPixel := WhiteIndex;
  1290.                     exit(GetFGPixel);
  1291.                 end;
  1292.             offset := ord4(v) * fgRowBytes + h;
  1293.             if offset >= ord4(fgHeight) * fgRowBytes then begin
  1294.                     GetFGPixel := WhiteIndex;
  1295.                     exit(GetFGPixel);
  1296.                 end;
  1297.                 p := ptr(ord4(ptr(fgSlotBase)) + offset);
  1298.             GetFGPixel := BAND(p^, 255);
  1299.         end;
  1300. end;
  1301.  
  1302.  
  1303. procedure WaitForTrigger;
  1304. begin
  1305.     StopDigitizing;
  1306.     ShowWatch;
  1307.     case FrameGrabber of
  1308.         QuickCapture:  begin
  1309.                 ControlReg^ := BitAnd($82, 255);  {Wait for external trigger and capture one frame}
  1310.                 repeat
  1311.                 until (BitAnd(ControlReg^, $80) = $00) or Button;  {Wait for it to complete}
  1312.             end;
  1313.         ScionLG3, ScionAg5, ScionVG5f:  begin
  1314.                 ControlReg^ := $90; {Wait for external trigger and capture one frame}
  1315.                 repeat
  1316.                 until (BitAnd(ControlReg^, $80) = $80) or Button;  {Wait for it to complete}
  1317.             end;
  1318.         otherwise
  1319.             repeat
  1320.             until Button;
  1321.     end;
  1322. end;
  1323.  
  1324.  
  1325. procedure DoVideoSettingsDialog;
  1326. {Displays QuickTime video digitizer options dialog box}
  1327.     const
  1328.         grayID = 6;
  1329.         color8ID = 7;
  1330.         color24ID = 8;
  1331.         fullID = 10;
  1332.         oneHalfID = 11;
  1333.         oneQuarterID = 12;
  1334.         ntscID = 14;
  1335.         palID = 15;
  1336.         secamID =16;
  1337.         builtinID = 17;
  1338.         sVideoID = 18;
  1339.     var
  1340.         mylog: DialogPtr;
  1341.         item, ignore: integer;
  1342.         saveScale: integer;
  1343.         saveBuiltin, sVideo: boolean;
  1344.         wasDigitizing, WindowClosed, vdigError: boolean;
  1345.         saveStandard: VideoDigitizerStandard;
  1346.         saveMode: VideoDigitizerMode;
  1347.         
  1348.     procedure SetCaptureModeButtons;
  1349.     begin
  1350.         SetDlogItem(mylog, grayID, ord(DigitizerMode = digitizeGrayscale));
  1351.         SetDlogItem(mylog, color8ID, ord(DigitizerMode = digitizeColor));
  1352.         SetDlogItem(mylog, color24ID, ord(DigitizerMode = digitizeRGB));
  1353.     end;
  1354.  
  1355.     procedure SetSizeButtons;
  1356.     begin
  1357.         SetDlogItem(mylog, fullID, ord(fgScale = 1));
  1358.         SetDlogItem(mylog, oneHalfID, ord(fgScale = 2));
  1359.         SetDlogItem(mylog, oneQuarterID, ord(fgScale = 4));
  1360.     end;
  1361.  
  1362.     procedure SetStandardButtons;
  1363.     begin
  1364.         SetDlogItem(mylog, ntscID, ord((DigitizerStandard = defaultStd) or (DigitizerStandard = NTSCStd)));
  1365.         SetDlogItem(mylog, palID, ord(DigitizerStandard = palStd));
  1366.         SetDlogItem(mylog, secamID, ord(DigitizerStandard = secamStd));
  1367.     end;
  1368.     
  1369. begin
  1370.     saveScale := fgScale;
  1371.     saveBuiltIn := UseBuiltinDigitizer;
  1372.     saveMode := DigitizerMode;
  1373.     saveStandard := DigitizerStandard;
  1374.     sVideo := VideoChannel = 1;
  1375.     InitCursor;
  1376.     mylog := GetNewDialog(320, nil, pointer(-1));
  1377.     SetCaptureModeButtons;
  1378.     SetSizeButtons;
  1379.     SetStandardButtons;
  1380.     SetDlogItem(mylog, builtinID, ord(UseBuiltinDigitizer));
  1381.     SetDlogItem(mylog, sVideoID, ord(sVideo));
  1382.     repeat
  1383.         ModalDialog(nil, item);
  1384.         if item = grayID then begin
  1385.             DigitizerMode := digitizeGrayscale;
  1386.             SetCaptureModeButtons;
  1387.         end;
  1388.         if item = color8ID then begin
  1389.             DigitizerMode := digitizeColor;
  1390.             SetCaptureModeButtons;
  1391.         end;
  1392.         if item = color24ID then begin
  1393.             DigitizerMode := digitizeRGB;
  1394.             SetCaptureModeButtons;
  1395.         end;
  1396.         if item = fullID then begin
  1397.             fgScale := 1;
  1398.             SetSizeButtons;
  1399.         end;
  1400.         if item = oneHalfID then begin
  1401.             fgScale := 2;
  1402.             SetSizeButtons;
  1403.         end;
  1404.         if item = oneQuarterID then begin
  1405.             fgScale := 4;
  1406.             SetSizeButtons;
  1407.         end;
  1408.         if item = ntscID then begin
  1409.             DigitizerStandard := ntscStd;
  1410.             SetStandardButtons;
  1411.         end;
  1412.         if item = palID then begin
  1413.             DigitizerStandard := palStd;
  1414.             SetStandardButtons;
  1415.         end;
  1416.         if item = secamID then begin
  1417.             DigitizerStandard := secamStd;
  1418.             SetStandardButtons;
  1419.         end;
  1420.         if item = builtinID then begin
  1421.             UseBuiltinDigitizer := not UseBuiltinDigitizer;
  1422.             SetDlogItem(mylog, builtinID, ord(UseBuiltinDigitizer));
  1423.         end;
  1424.         if item = sVideoID then begin
  1425.             sVideo := not sVideo;
  1426.             SetDlogItem(mylog, sVideoID, ord(sVideo));
  1427.         end;
  1428.     until (item = ok) or (item = cancel);
  1429.     DisposeDialog(mylog);
  1430.     if item = cancel then begin
  1431.         fgScale := saveScale;
  1432.         UseBuiltinDigitizer := saveBuiltIn;
  1433.         DigitizerMode := saveMode;
  1434.         DigitizerStandard := saveStandard;
  1435.         exit(DoVideoSettingsDialog);
  1436.     end;
  1437.     if sVideo then
  1438.         VideoChannel := 1
  1439.     else
  1440.         VideoChannel := 0;
  1441.     wasDigitizing := digitizing;
  1442.     StopDigitizing;
  1443.     WindowClosed := false;
  1444.     CloseVdig;
  1445.     if (fgScale <> saveScale) or (UseBuiltinDigitizer <> saveBuiltIn) or (DigitizerStandard <> saveStandard) then begin
  1446.         SelectCameraWindow;
  1447.         with info^ do if PictureType = FrameGrabberType then begin
  1448.             changes := false;
  1449.             ignore := CloseAWindow(wptr);
  1450.             WindowClosed := true;
  1451.         end;
  1452.     end;
  1453.     if FrameGrabber = NoFrameGrabber then
  1454.         LookForVDig(vdigError);
  1455.     if wasDigitizing or WindowClosed then
  1456.         StartDigitizing;
  1457. end;
  1458.  
  1459.  
  1460. procedure SetOffset (var offset, gain: integer);
  1461. begin
  1462.     if offset < 0 then
  1463.         offset := 0;
  1464.     if offset > 255 then
  1465.         offset := 255;
  1466.     if offset > gain then
  1467.         offset := gain;
  1468.     DacLow := offset;
  1469.     DacHigh := DacLow + (255 - gain);
  1470. end;
  1471.  
  1472.  
  1473. procedure SetGain (var offset, gain: integer);
  1474. begin
  1475.     if gain < 0 then
  1476.         gain := 0;
  1477.     if gain > 255 then
  1478.         gain := 255;
  1479.     if gain < DacLow then
  1480.         gain := DacLow;
  1481.     DacHigh := DacLow + (255 - gain);
  1482. end;
  1483.  
  1484.  
  1485. procedure ShowChannel;
  1486. begin
  1487.     SetDlogItem(VideoControl, FirstChannelID, ord(VideoChannel = 0));
  1488.     SetDlogItem(VideoControl, FirstChannelID + 1, ord(VideoChannel = 1));
  1489.     SetDlogItem(VideoControl, FirstChannelID + 2, ord(VideoChannel = 2));
  1490.     SetDlogItem(VideoControl, FirstChannelID + 3, ord(VideoChannel = 3));
  1491. end;
  1492.  
  1493.  
  1494. procedure UpdateVideoControl;
  1495. begin
  1496.     if VideoControl <> nil then
  1497.         SetDlogItem(VideoControl, TriggerID, ord(ExternalTrigger));
  1498. end;
  1499.  
  1500.  
  1501. procedure ShowOffsetAndGain (offset, gain: integer);
  1502.     var
  1503.         str: str255;
  1504. begin
  1505.     RealToString(offset, 3, 0, str);
  1506.     if str[1] = ' ' then
  1507.         str[1] := '0';
  1508.     if str[2] = ' ' then
  1509.         str[2] := '0';
  1510.     SetDString(VideoControl, OffsetID, str);
  1511.     RealToString(gain, 3, 0, str);
  1512.     if str[1] = ' ' then
  1513.         str[1] := '0';
  1514.     if str[2] = ' ' then
  1515.         str[2] := '0';
  1516.     SetDString(VideoControl, GainID, str);
  1517. end;
  1518.  
  1519.  
  1520. procedure ShowVideoControl;
  1521.     var
  1522.         gain: integer;
  1523. begin
  1524.     InitCursor;
  1525.     VideoControl := GetNewDialog(130, nil, pointer(-1));
  1526.     ShowChannel;
  1527.     SetDlogItem(VideoControl, InvertID, ord(InvertVideo));
  1528.     SetDlogItem(VideoControl, HighlightID, ord(HighlightSaturatedPixels));
  1529.     SetDlogItem(VideoControl, TriggerID, ord(ExternalTrigger));
  1530.     SetDlogItem(VideoControl, SyncID, ord(SyncMode = SeparateSync));
  1531.     gain := 255 - (DacHigh - DacLow);
  1532.     ShowOffsetAndGain(DacLow, gain);
  1533. end;
  1534.  
  1535.  
  1536.     function NoScion:boolean;
  1537.     var
  1538.         NotFound:boolean;
  1539.     begin
  1540.         NotFound:=(FrameGrabber <> ScionLG3) and (FrameGrabber<>ScionAg5) and (FrameGrabber<>ScionVG5f);
  1541.         if NotFound then PutError('Programmable offset and gain are only supported on Scion frame grabbers.');
  1542.         NoScion:=NotFound;
  1543.     end;
  1544.  
  1545.  
  1546.     procedure DoVideoControl (item: integer);
  1547.     var
  1548.         i: integer;
  1549.         OutOfRange, WasDigitizing: boolean;
  1550.         offset, gain, inc, count: integer;
  1551.  
  1552.  
  1553.     procedure SetVideoItem (item, value: integer);
  1554.     begin
  1555.         if VideoControl <> nil then
  1556.             SetDlogItem(VideoControl, item, value);
  1557.     end;
  1558.  
  1559. begin
  1560.     InitCursor;
  1561.     gain := 255 - (DacHigh - DacLow);
  1562.     if (item >= FirstChannelID) and (item <= (FirstChannelID + 3)) then begin
  1563.             VideoChannel := item - FirstChannelID;
  1564.             if VideoControl <> nil then
  1565.                 ShowChannel;
  1566.             if digitizing then
  1567.                 ResetFrameGrabber;
  1568.         end;
  1569.     if item = InvertID then begin
  1570.             InvertVideo := not InvertVideo;
  1571.             SetVideoItem(InvertID, ord(InvertVideo));
  1572.             if digitizing then
  1573.                 ResetFrameGrabber;
  1574.         end;
  1575.     if item = HighlightID then begin
  1576.             HighlightSaturatedPixels := not HighlightSaturatedPixels;
  1577.             SetVideoItem(HighlightID, ord(HighlightSaturatedPixels));
  1578.             if digitizing then begin
  1579.                     if HighlightSaturatedPixels then
  1580.                         HighlightPixels
  1581.                     else
  1582.                         LoadLUT(info^.ctable);
  1583.                 end;
  1584.         end;
  1585.     if item = TriggerID then begin
  1586.             ExternalTrigger := not ExternalTrigger;
  1587.             case FrameGrabber of
  1588.                 QuickCapture, ScionLG3, ScionAG5, ScionVG5f:  begin
  1589.                         WasDigitizing := digitizing;
  1590.                         StopDigitizing;
  1591.                         if ExternalTrigger and WasDigitizing then
  1592.                             StartDigitizing;
  1593.                     end;
  1594.                 otherwise
  1595.                     ExternalTrigger := false;
  1596.             end;
  1597.             SetVideoItem(TriggerID, ord(ExternalTrigger));
  1598.         end;
  1599.     if item = SyncID then begin
  1600.             if SyncMode <> SeparateSync then
  1601.                 SyncMode := SeparateSync
  1602.             else
  1603.                 SyncMode := NormalSync;
  1604.             case FrameGrabber of
  1605.                 ScionLG3, ScionAG5, ScionVG5f: 
  1606.                     if digitizing then
  1607.                         ResetFrameGrabber;
  1608.                 QuickCapture:  begin
  1609.                         PutError('Sync is not under program control on the QuickCapure card.');
  1610.                         SyncMode := NormalSync;
  1611.                         AbortMacro;
  1612.                     end;
  1613.                 otherwise
  1614.                     ;
  1615.             end;
  1616.             SetVideoItem(SyncID, ord(SyncMode = SeparateSync));
  1617.         end;
  1618.     if (item >= OffsetUpID) and (item <= GainDownID) then begin
  1619.             if NoScion then exit(DoVideoControl);
  1620.             offset := DacLow;
  1621.             inc := 1;
  1622.             count := 0;
  1623.             repeat
  1624.                 count := count + 1;
  1625.                 if count > 2 then
  1626.                     inc := 2;
  1627.                 if count > 4 then
  1628.                     inc := 5;
  1629.                 if count > 8 then
  1630.                     inc := 10;
  1631.                 case item of
  1632.                     OffsetUpID:  begin
  1633.                             offset := offset + inc;
  1634.                             SetOffset(offset, gain);
  1635.                         end;
  1636.                     OffsetDownID:  begin
  1637.                             offset := offset - inc;
  1638.                             SetOffset(offset, gain);
  1639.                         end;
  1640.                     GainUpID:  begin
  1641.                             gain := gain + inc;
  1642.                             SetGain(offset, gain);
  1643.                         end;
  1644.                     GainDownID:  begin
  1645.                             gain := gain - inc;
  1646.                             SetGain(offset, gain);
  1647.                         end;
  1648.                 end; {case}
  1649.                 ShowOffsetAndGain(DacLow, gain);
  1650.                 if Digitizing and (count > 1) then begin
  1651.                         DacLowReg^ := DacLow;
  1652.                         DacHighReg^ := DacHigh;
  1653.                         CaptureAndDisplayFrame;
  1654.                         if ContinuousHistogram then begin
  1655.                                 ShowContinuousHistogram;
  1656.                                 DrawHistogram
  1657.                             end
  1658.                     end
  1659.                 else
  1660.                     wait(5);
  1661.             until not button;
  1662.         end;
  1663.     if item = ResetID then begin
  1664.             if NoScion then exit(DoVideoControl);
  1665.             DacLow := DefaultDacLow;
  1666.             DacHigh := DefaultDacHigh;
  1667.             gain := 255 - (DacHigh - DacLow);
  1668.             ParamText(long2str(DacLow), long2str(gain), '', '');
  1669.             ShowOffsetAndGain(DacLow, gain);
  1670.         end;
  1671.     if FramesToAverage < 2 then
  1672.         FramesToAverage := 2;
  1673.     if (FrameGrabber = ScionLG3) or (FrameGrabber=ScionAG5) or (FrameGrabber=ScionVG5f) then begin
  1674.             DacLowReg^ := DacLow;
  1675.             DacHighReg^ := DacHigh;
  1676.         end;
  1677. end;
  1678.  
  1679.  
  1680. procedure ShowVideoDialog;
  1681. var
  1682.     vdigError: boolean;
  1683. begin
  1684.     if FrameGrabber = noFrameGrabber then begin
  1685.         LookForVDig(vdigError);
  1686.         if vdigError then begin
  1687.             doVideoSettingsDialog;
  1688.             exit(ShowVideoDialog);
  1689.         end;
  1690.     end;
  1691.     if FrameGrabber = QTvdig then
  1692.         doVideoSettingsDialog
  1693.     else begin
  1694.         if VideoControl = nil then
  1695.             ShowVideoControl
  1696.         else
  1697.             SelectWindow(VideoControl);
  1698.     end;
  1699. end;
  1700.  
  1701. end.